package com.huatai.saas.service;


import com.huatai.common.config.MinioAPI;
import com.huatai.common.error.exception.ServiceException;
import com.huatai.common.util.DateTimeUtil;

import com.huatai.saas.constant.MinioBucket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.List;
/**
 * @author xuzy
 */
@Service
@Slf4j
public class FileService {

	@Autowired
	private MinioAPI minioAPI;



	private final static String SLASH = "/";
	private final static String FILE_NAME_PREFIX_SEPARATOR = "-";

	@Value("${privateBucket.fileType}")
	List<String> privateBucketNameFileSufix;

	private final static long FILE_DOWNLOAD_ZISE = 1024 * 1024 * 10;



	/**
	 * 文件普通上传
	 */
	public String upload(MultipartFile file) {
		try(InputStream is = file.getInputStream()) {
			String bucketName = getBucketName(file.getOriginalFilename());
			String objectKey = getObjectKey(file.getSize(),file.getOriginalFilename());
			minioAPI.uploadInputStream(bucketName, objectKey, is, file.getContentType());
			return objectKey;
		} catch (Exception e) {
			log.error("上传失败，", e);
			throw new ServiceException("上传失败，请重新上传");
		}
	}

	//下载文件
	public void download(String fileUrl){
		this.download(fileUrl,null,null);
	}

	/**
	 * 根据分片索引下载
	 * @param fileUrl
	 * @param partIndex
	 */
	public void download(String fileUrl,int partIndex){
		Long offset = ((partIndex-1) * FILE_DOWNLOAD_ZISE);
		download(fileUrl,offset,FILE_DOWNLOAD_ZISE);
	}

	/**
	 * 根据偏移量下载
	 * @param fileUrl
	 * @param offset
	 * @param length
	 */
	public void download(String fileUrl, Long offset, Long length){
		HttpServletResponse response =
			((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();

		InputStream inputStream = null;
		OutputStream out = null;
		try {
			String bucketName = getBucketName(fileUrl);
			if(null ==offset || null == length){//原文件下载
				inputStream = minioAPI.download(bucketName,fileUrl);
			}else{//分片下载
				inputStream = minioAPI.partDownload(bucketName,fileUrl,offset,length);
			}

			//获取下载文本长度，如果是分片下载，计算分片大小（重新计算最后一片分片大小）
			Long totleSize = minioAPI.getFileSize(bucketName,fileUrl);
			if(null == offset){
				length = totleSize;
			}else{
				if(totleSize < offset + length){
					length = totleSize-offset;
				}
			}

			byte[] buf = new byte[1024*1024];
			int len = 0;

			response.reset();
			response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUrl.substring(fileUrl.indexOf(FILE_NAME_PREFIX_SEPARATOR) + 1), "UTF-8"));
			response.setContentType("application/octet-stream");
			response.setCharacterEncoding("UTF-8");
			//response.setContentLengthLong(totleSize.intValue());
			response.setContentLengthLong(length);
			response.setHeader("file-size",String.valueOf(totleSize.longValue()));
			if(null != offset ){
				response.setHeader("Content-Length-Total",String.valueOf(totleSize));
			}
			out = response.getOutputStream();
			while ((len = inputStream.read(buf)) != -1){
				out.write(buf, 0, len);
			}
			out.flush();
			out.close();
			inputStream.close();
		} catch (Exception e) {
			log.error("文件下载失败,失败原因:{}",e.getMessage());
			response.setHeader("Content-type", "text/html;charset=UTF-8");
			response.setStatus(500);
			String data = "文件下载失败";
			try {
				if(out == null){
					out = response.getOutputStream();
				}
				out.write(data.getBytes("UTF-8"));
			}catch (Exception e1){}
		}finally {
			try {
				if (inputStream != null) {
					inputStream.close();
				}
				if (out != null) {
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * 获取分片数
	 * @param fileUrl
	 * @return
	 */
	public int getFilePartNums(String fileUrl){
		Long totleSize = getFileSize(fileUrl);
		return (int)Math.ceil((totleSize / (double)FILE_DOWNLOAD_ZISE));
	}

	/**
	 * 获取文件大小
	 * @param fileUrl
	 * @return
	 */
	public Long getFileSize(String fileUrl){
		try {
			String bucketName = getBucketName(fileUrl);
			return minioAPI.getFileSize(bucketName,fileUrl);
		}catch (Exception e){
			throw new ServiceException(e.getMessage());
		}
	}



	/**
	 * 获取存储路径
	 * @param fileSize
	 * @param fileName
	 * @return
	 */
	private String getObjectKey(Long fileSize,String fileName) {
		String date = DateTimeUtil.format(LocalDate.now(),"yyyyMMdd");

		StringBuilder objectKey = new StringBuilder(date);
		objectKey.append(SLASH).append(fileSize).append(FILE_NAME_PREFIX_SEPARATOR).append(fileName);
		return objectKey.toString();
	}

	/**
	 * 获取文件存储bucket
	 * @param fileName
	 * @return
	 */
	public String getBucketName(String fileName){
		String sufix = fileName.substring(fileName.lastIndexOf(".")+1);
		return privateBucketNameFileSufix.contains(sufix) ? MinioBucket.MODEL_BUCKET_NAME_PRIVATE : MinioBucket.MODEL_BUCKET_NAME_PUBLIC;
	}
}
